﻿Imports System
Imports System.Drawing
Imports System.Windows.Forms

Namespace System.Workflow.ComponentModel.Design
    Friend NotInheritable Class AutoScrollingMessageFilter
        Inherits WorkflowDesignerMessageFilter
        ' Methods
        Friend Sub New()
        End Sub

        Private Function AutoScrollDirectionFromPoint(ByVal clientPoint As Point) As ScrollDirection
            Dim rectangle As New Rectangle(Point.Empty, MyBase.ParentView.ViewPortSize)
            If Not rectangle.Contains(clientPoint) Then
                Return ScrollDirection.None
            End If
            Dim none As ScrollDirection = ScrollDirection.None
            Dim hScrollBar As ScrollBar = MyBase.ParentView.HScrollBar
            If ((clientPoint.X <= (rectangle.Width / 10)) AndAlso (hScrollBar.Value > 0)) Then
                none = (none Or ScrollDirection.Left)
            ElseIf ((clientPoint.X >= (rectangle.Right - (rectangle.Width / 10))) AndAlso (hScrollBar.Value < (hScrollBar.Maximum - hScrollBar.LargeChange))) Then
                none = (none Or ScrollDirection.Right)
            End If
            Dim vScrollBar As ScrollBar = MyBase.ParentView.VScrollBar
            If ((clientPoint.Y <= (rectangle.Height / 10)) AndAlso (vScrollBar.Value > 0)) Then
                Return (none Or ScrollDirection.Up)
            End If
            If ((clientPoint.Y >= (rectangle.Bottom - (rectangle.Height / 10))) AndAlso (vScrollBar.Value < (vScrollBar.Maximum - vScrollBar.LargeChange))) Then
                none = (none Or ScrollDirection.Down)
            End If
            Return none
        End Function

        Private Sub DrawScrollIndicators(ByVal graphics As Graphics)
            Dim scrollIndicatorImage As Image = AmbientTheme.ScrollIndicatorImage
            If (Not scrollIndicatorImage Is Nothing) Then
                Dim parentView As WorkflowView = MyBase.ParentView
                Dim viewPortSize As Size = parentView.ViewPortSize
                Dim scrollPosition As Point = parentView.ScrollPosition
                Dim scrollIndicatorRectangles As Rectangle() = Me.ScrollIndicatorRectangles
                If (scrollPosition.X > 0) Then
                    ActivityDesignerPaint.DrawImage(graphics, AmbientTheme.ScrollIndicatorImage, scrollIndicatorRectangles(0), CSng(0.7!))
                End If
                If (scrollPosition.X < (parentView.HScrollBar.Maximum - viewPortSize.Width)) Then
                    scrollIndicatorImage.RotateFlip(RotateFlipType.RotateNoneFlipX)
                    ActivityDesignerPaint.DrawImage(graphics, scrollIndicatorImage, scrollIndicatorRectangles(1), CSng(0.7!))
                    scrollIndicatorImage.RotateFlip(RotateFlipType.RotateNoneFlipX)
                End If
                If (scrollPosition.Y > 0) Then
                    scrollIndicatorImage.RotateFlip(RotateFlipType.Rotate90FlipX)
                    ActivityDesignerPaint.DrawImage(graphics, scrollIndicatorImage, scrollIndicatorRectangles(2), CSng(0.7!))
                    scrollIndicatorImage.RotateFlip(RotateFlipType.Rotate90FlipX)
                End If
                If (scrollPosition.Y < (parentView.VScrollBar.Maximum - viewPortSize.Height)) Then
                    scrollIndicatorImage.RotateFlip(RotateFlipType.Rotate270FlipNone)
                    ActivityDesignerPaint.DrawImage(graphics, scrollIndicatorImage, scrollIndicatorRectangles(3), CSng(0.7!))
                    scrollIndicatorImage.RotateFlip(RotateFlipType.Rotate90FlipNone)
                End If
            End If
        End Sub

        Private Sub OnAutoScroll(ByVal sender As Object, ByVal eventArgs As EventArgs)
            Dim parentView As WorkflowView = MyBase.ParentView
            Dim scrollPosition As Point = parentView.ScrollPosition
            If ((Me.autoScrollDirection And ScrollDirection.Left) > DirectCast(0, ScrollDirection)) Then
                scrollPosition.X = (scrollPosition.X - &H19)
            ElseIf ((Me.autoScrollDirection And ScrollDirection.Right) > DirectCast(0, ScrollDirection)) Then
                scrollPosition.X = (scrollPosition.X + &H19)
            End If
            If ((Me.autoScrollDirection And ScrollDirection.Up) > DirectCast(0, ScrollDirection)) Then
                scrollPosition.Y = (scrollPosition.Y - &H19)
            ElseIf ((Me.autoScrollDirection And ScrollDirection.Down) > DirectCast(0, ScrollDirection)) Then
                scrollPosition.Y = (scrollPosition.Y + &H19)
            End If
            parentView.ScrollPosition = scrollPosition
        End Sub

        Protected Overrides Function OnDragDrop(ByVal eventArgs As DragEventArgs) As Boolean
            Me.startAutoScroll = False
            Me.AutoScrollDirection = ScrollDirection.None
            Return False
        End Function

        Protected Overrides Function OnDragEnter(ByVal eventArgs As DragEventArgs) As Boolean
            Me.startAutoScroll = True
            Dim rectangle As Rectangle
            For Each rectangle In Me.ScrollIndicatorRectangles
                MyBase.ParentView.InvalidateClientRectangle(rectangle)
            Next
            Return False
        End Function

        Protected Overrides Function OnDragLeave() As Boolean
            Me.startAutoScroll = False
            Me.AutoScrollDirection = ScrollDirection.None
            Return False
        End Function

        Protected Overrides Function OnDragOver(ByVal eventArgs As DragEventArgs) As Boolean
            Me.startAutoScroll = True
            Dim clientPoint As Point = MyBase.ParentView.PointToClient(New Point(eventArgs.X, eventArgs.Y))
            Me.AutoScrollDirection = Me.AutoScrollDirectionFromPoint(clientPoint)
            Return (Me.AutoScrollDirection <> ScrollDirection.None)
        End Function

        Protected Overrides Function OnPaintWorkflowAdornments(ByVal e As PaintEventArgs, ByVal viewPort As Rectangle, ByVal ambientTheme As AmbientTheme) As Boolean
            If Me.ShowAutoScrollIndicators Then
                Me.DrawScrollIndicators(e.Graphics)
            End If
            Return False
        End Function


        ' Properties
        Private Property AutoScrollDirection As ScrollDirection
            Get
                Return Me.autoScrollDirection
            End Get
            Set(ByVal value As ScrollDirection)
                If (Me.autoScrollDirection <> value) Then
                    Me.autoScrollDirection = value
                    Dim rectangle As Rectangle
                    For Each rectangle In Me.ScrollIndicatorRectangles
                        MyBase.ParentView.InvalidateClientRectangle(rectangle)
                    Next
                    If (ScrollDirection.None = value) Then
                        If (Not Me.autoScrollEventHandler Is Nothing) Then
                            WorkflowTimer.Default.Unsubscribe(Me.autoScrollEventHandler)
                            Me.autoScrollEventHandler = Nothing
                        End If
                    ElseIf (Me.autoScrollEventHandler Is Nothing) Then
                        Me.autoScrollEventHandler = New EventHandler(AddressOf Me.OnAutoScroll)
                        WorkflowTimer.Default.Subscribe(50, Me.autoScrollEventHandler)
                    End If
                End If
            End Set
        End Property

        Private ReadOnly Property ScrollIndicatorRectangles As Rectangle()
            Get
                Dim rectangle As New Rectangle(Point.Empty, MyBase.ParentView.ViewPortSize)
                Dim margin As Size = WorkflowTheme.CurrentTheme.AmbientTheme.Margin
                Dim scrollIndicatorSize As Size = WorkflowTheme.CurrentTheme.AmbientTheme.ScrollIndicatorSize
                Dim rectangleArray As Rectangle() = New Rectangle(4  - 1) {}
                rectangleArray(0).X = margin.Width
                rectangleArray(0).Y = ((rectangle.Height - scrollIndicatorSize.Height) / 2)
                rectangleArray(0).Size = scrollIndicatorSize
                rectangleArray(1).X = ((rectangle.Right - margin.Width) - scrollIndicatorSize.Width)
                rectangleArray(1).Y = ((rectangle.Height - scrollIndicatorSize.Height) / 2)
                rectangleArray(1).Size = scrollIndicatorSize
                rectangleArray(2).X = ((rectangle.Width - scrollIndicatorSize.Width) / 2)
                rectangleArray(2).Y = margin.Height
                rectangleArray(2).Size = scrollIndicatorSize
                rectangleArray(3).X = ((rectangle.Width - scrollIndicatorSize.Width) / 2)
                rectangleArray(3).Y = ((rectangle.Bottom - margin.Height) - scrollIndicatorSize.Height)
                rectangleArray(3).Size = scrollIndicatorSize
                Return rectangleArray
            End Get
        End Property

        Private ReadOnly Property ShowAutoScrollIndicators As Boolean
            Get
                Dim ambientTheme As AmbientTheme = WorkflowTheme.CurrentTheme.AmbientTheme
                If Not Me.startAutoScroll Then
                    Return False
                End If
                Dim viewPortSize As Size = MyBase.ParentView.ViewPortSize
                Dim scrollIndicatorSize As Size = ambientTheme.ScrollIndicatorSize
                scrollIndicatorSize.Width = (scrollIndicatorSize.Width + (2 * ambientTheme.Margin.Width))
                scrollIndicatorSize.Height = (scrollIndicatorSize.Height + (2 * ambientTheme.Margin.Height))
                Return ((viewPortSize.Width > (2 * scrollIndicatorSize.Width)) AndAlso (viewPortSize.Height > (2 * scrollIndicatorSize.Height)))
            End Get
        End Property


        ' Fields
        Private autoScrollDirection As ScrollDirection = ScrollDirection.None
        Private autoScrollEventHandler As EventHandler
        Private startAutoScroll As Boolean

        ' Nested Types
        Private Enum ScrollDirection
            ' Fields
            Down = &H10
            Left = 2
            None = 1
            Right = 8
            Up = 4
        End Enum
    End Class
End Namespace

